package rensoft.android.view.requestdata;

import static rensoft.android.lang.AndroidLang.event;
import static rensoft.java.lang.Lang.is;

import rensoft.android.rpc.IServerRequest;
import rensoft.java.event.Event;
import rensoft.java.event.Event.EventRegistration;
import rensoft.java.event.Listener;
import rensoft.java.lang.Base;
import rensoft.java.lang.Callback;

public abstract class RequestData<T extends IServerRequest> extends Base implements IRequestData<T> {
  protected T request;
  private final Event<T> eventLoaded = event();
  private final Event<Void> eventFailed = event();
  private boolean waiting;

  private Callback<T> createRequestListener;

  public Event<Void> eventFailed() {
    return eventFailed;
  }

  public Event<T> eventLoaded() {
    return eventLoaded;
  }

  @Override
  public T getDataRequest() {
    return request;
  }

  @Override
  public boolean isReady() {
    return !waiting && is(request);
  }

  public void load() {
    T newRequest = createRequest();
    if (newRequest.isEqual(request)) {
      if (request.isDone()) {
        waiting = false;
        fire(eventLoaded, request);
      } else loadLater();
    } else {
      request = newRequest;
      if (is(createRequestListener)) createRequestListener.onCall(request);
      loadLater();
      request.send();
      waiting = true;
    }

  }

  public void reload() {
    request = null;
    load();
  }

  @Override
  public void setCreateRequestListener(Callback<T> callback) {
    createRequestListener = callback;
  }

  protected abstract T createRequest();

  private void loadLater() {
    final T request = this.request;
    listenOnce(request.eventLoaded(), new Listener<Void>() {
      public void onEvent(EventRegistration registration, Void arg) {
        if (request != RequestData.this.request) return;
        waiting = false;
        fire(eventLoaded, request);
      }
    });
    listenOnce(request.eventFailed(), new Listener<Void>() {
      public void onEvent(EventRegistration registration, Void arg) {
        if (request != RequestData.this.request) return;
        waiting = false;
        fire(eventFailed);
      }
    });
  }
}
